package validator

import (
	"errors"
	"fmt"
	"gopkg.in/go-playground/validator.v9"
	"regexp"
)

const (
	passwordSizePattern         = `^\S{8,32}$`
	passwordUpperPattern        = `^\S*[A-Z]+\S*$`
	passwordLowerPattern        = `^\S*[a-z]+\S*$`
	passwordSpecialOrNumPattern = `^\S*[0-9~!@#$%^&*()_+-=\[\]|;':",./<>?]+\S*$`
)

var (
	passwordSizeRegex         = regexp.MustCompile(passwordSizePattern)
	passwordUpperRegex        = regexp.MustCompile(passwordUpperPattern)
	passwordLowerRegex        = regexp.MustCompile(passwordLowerPattern)
	passwordSpecialOrNumRegex = regexp.MustCompile(passwordSpecialOrNumPattern)
	ErrPasswordValidation     = errors.New("invalid password")
	ErrPasswordSize           = fmt.Errorf("%w:password size not between 8 and 32", ErrPasswordValidation)
	ErrPasswordNoUpper        = fmt.Errorf("%w:no upper character", ErrPasswordValidation)
	ErrPasswordNoLower        = fmt.Errorf("%w:no lower character", ErrPasswordValidation)
	ErrPasswordNoSpecialOrNum = fmt.Errorf("%w:no special or numberical character", ErrPasswordValidation)
)

func PasswordValidateFunc(fl validator.FieldLevel) bool {
	pw := fl.Field().String()
	if err := PasswordValidate(pw); err != nil {
		return false
	}
	return true
}

func PasswordValidate(pw string) error {
	if !passwordSizeRegex.MatchString(pw) {
		return ErrPasswordSize
	}
	if !passwordUpperRegex.MatchString(pw) {
		return ErrPasswordNoUpper
	}
	if !passwordLowerRegex.MatchString(pw) {
		return ErrPasswordNoLower
	}
	if !passwordSpecialOrNumRegex.MatchString(pw) {
		return ErrPasswordNoSpecialOrNum
	}
	return nil
}
